#ifndef _CANARY2_NET_SOCK_H_
#define _CANARY2_NET_SOCK_H_

#include "ipaddr.h"

#include <sys/socket.h>
#include <netinet/in.h>
#include <variant>
#include <span>
#include "../sys/fd_guard.h"

namespace wilson::net
{
    class socket
    {
    public:
        enum type_t : int { 
            NOTHING = 0, TCP = SOCK_STREAM, UDP = SOCK_DGRAM 
        };

        constexpr socket() = default;

        socket(ipv4_address a, in_port_t port);
        socket(ipv6_address a, in_port_t port);

        ::std::string to_string() const;
        constexpr socklen_t posix_socklen() const
        {
            return s_ipaddr.index() == 0 ? 
                sizeof(sockaddr_in) : sizeof(sockaddr_in6);
        }

        void posix_sockaddr(sockaddr* sock, socklen_t len);
        void bind_as_tcp();
        void bind_as_udp();
        void reuse_port();
        void reuse_addr();
        void close() { s_sockfd.close(); }
        constexpr int family() const
            { return s_ipaddr.index() == 0 ? AF_INET : AF_INET6; }
        constexpr int type() const { return s_type; }
        sys::borrowed_fd fd() const noexcept { return s_sockfd; }
        
    private:
        ::std::variant<ipv4_address, ipv6_address> s_ipaddr;
        in_port_t s_port{};
        wilson::sys::fd_guard s_sockfd;
        type_t s_type{};
    };
}

#endif
